
// Object.preventExtensions 禁止扩展
// Object.isExtensible 判断一个对象是否是可扩展的

// 'use strict';

// const obj = {
//   a: 1,
//   b: 2
// };

// const newObj = Object.preventExtensions(obj);
// console.log(newObj);
// console.log(newObj === obj); // true
// const res = Object.isExtensible(obj);
// console.log(res);

// obj.c = 1; // 严格模式下报错 Cannot add property c, object is not extensible

// obj.a = 111; // 可修改
// delete obj.a; // 可删除

// 无法定义 Cannot define property a, object is not extensible
// Object.defineProperty(obj, 'c', {
//   value: 1,
//   writable: true,
//   configurable: true
// })

// console.log(obj);

// const newObj = Object.preventExtensions(1);
// const newObj = Object.preventExtensions('1');
// const newObj = Object.preventExtensions(null);
// console.log(newObj);

// const obj = {
//   a: 1,
//   b: 2
// }

// Object.prototype.c = 3;
// Object.preventExtensions(obj);

// obj.__proto__.c = 333; // 原型上的属性可以修改
// Object.prototype.c = 444;

// obj.__proto__.d = 444; // 原型上的属性可扩展
// Object.prototype.e = 555;

// delete obj.__proto__.c; // 原型上的属性可删除

// obj.__proto__ = { // 原型不可更改 TypeError: #<Object> is not extensible
//   x: 'xxx'
// }

// Object.prototype = { // 声明obj时已经实例化Object了，不可更改
//   x: 'xxx'
// }

// console.log(obj);


// const arr = [1, 2, 3];
// Object.preventExtensions(arr);

// console.log(Object.isExtensible(arr));

// arr[0] = 111; // 可修改
// delete arr[1]; // 可删除
// arr.splice(1, 1);
// arr.push(4); // 不可扩展 TypeError: Cannot add property 3, object is not extensible
// console.log(arr);

const obj = {
  a: 1,
  b: 2,
  c: {
    d: 4,
    e: {
      f: 5
    }
  }
}

// Object.preventExtensions(obj);

// obj.c.x = 'xxx'; // 可扩展
// console.log(obj);

// 实现深度不可扩展
Object.deepPreventExtensions = function (obj) {
  const _keys = Object.getOwnPropertyNames(obj);

  if (_keys.length) {
    _keys.forEach(k => {
      const _v = obj[k];
      if (typeof _v === 'object' && _v !== null) {
        Object.deepPreventExtensions(_v)
      }
    })
  }

  return Object.preventExtensions(obj);
}


Object.deepPreventExtensions(obj);

obj.c.x = 'xxx'; // 不可扩展
console.log(obj);


/**
 * Object.preventExtensions 禁止扩展
 * 让一个对象变的不可扩展，也就是永远不能再添加新的属性。并且返回原对象
 * 
 * 除不可扩展外，其他属性会保留
 * 
 * 尝试将新属性添加将静默失败，严格模式下报错 Cannot add property a, object is not extensible
 * 
 * 不可再定义属性、原型。但原型上的属性可扩展、可修改、可删除
 * 
 * ES5中 如果参数不是一个对象类型 将抛出TypeError 异常
 * ES2015中 会视为不可扩展的普通对象 直接返回本身
 * 
 * 与 Object.freeze()、Object.seal() 一样是浅修改对象
 * 
 * freeze: 不可修改、不可删除、不可扩展
 * seal: 可修改、不可删除、不可扩展
 * preventExtensions: 可修改、可删除、不可扩展
 * 
 */




// 新对象默认是可扩展的.
// const empty = {};
// const obj = {
//   a: 1
// };
// console.log(empty);

// ...可以变的不可扩展.
// Object.preventExtensions(empty);
// console.log(Object.isExtensible(empty)); // === false
// console.log(Object.isSealed(empty)); // === true // 一个空对象被变得不可扩展，那说明也是封闭、冻结对象
// console.log(Object.isFrozen(empty)); // === true

// Object.preventExtensions(obj);
// console.log(Object.isExtensible(obj)); // === false
// console.log(Object.isSealed(obj)); // === false // 一个非空对象被变得不可扩展，但不会变成封闭、冻结对象
// console.log(Object.isFrozen(obj)); // === false

// 密封对象是不可扩展的.
// const sealed = Object.seal({});
// Object.isExtensible(sealed); // === false

// 冻结对象也是不可扩展.
// const frozen = Object.freeze({});
// Object.isExtensible(frozen); // === false

// const obj = {
//   a: 1
// };

// Object.preventExtensions(obj);
// 不可扩展、不可写、可删除
// Object.defineProperty(obj, 'a', {
//   writable: false,
//   configurable: false
// })
// delete obj.a;
// console.log(obj);

// 不可扩展、不可写、不可删除
// console.log(Object.isFrozen(obj));
// 不可扩展，可写、不可删除
// console.log(Object.isSealed(obj));

// const o = {a: 1};
// Object.freeze(o);
// Object.seal(o);
// console.log(Object.isFrozen(o));
// console.log(Object.isSealed(o)); // true 是冻结对象就一定是封闭对象
// console.log(Object.isExtensible(o));

// const obj = {
//   get a() {
//     return 1;
//   }
// }
// obj.a = 2; // 不可写
// delete obj.a; // 可删除

// console.log(obj);
// Object.preventExtensions(obj);
// console.log(Object.isFrozen(obj)); // 如果把里面的a 删除了 就是空对象，为true
// console.log(Object.isSealed(obj)); // 如果把里面的a 删除了 就是空对象，为true
// console.log(Object.isExtensible(obj));


/**
 * Object.isExtensible 判断一个对象是否是可扩展
 * 
 * 一个空对象被变得不可扩展，那说明也是封闭、冻结对象
 * 一个非空对象被变得不可扩展，但不会变成封闭、冻结对象
 * 
 * ES5中 如果参数不是一个对象类型 将抛出TypeError 异常
 * ES2015中 会视为不可扩展的普通对象 返回false
 * 
 */
